#include "header.h"
#include "./Libs/General.h"
#include <mpi.h>

int main(int argc, char *argv[]) {
  int i,j,size,rank;
  int x_points, from_point, to_point;
  MPI_Status stat;
  double ***ar,*temp;

  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD,&size); 
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);

  temp = (double *)malloc((ysteps-2)*sizeof(double));
  x_points = get_mynums(size, rank);
  from_point = get_fromnum(size, rank);
  to_point = from_point + x_points;

  ar = InitializeArray(ar,x_points);
  for(i=0;i<ysteps;++i)
    for(j=1;j<=x_points;++j)
      ar[0][i][j] = 10*i+j;

  printf("rank is %d, input\n",rank);
  for(i=0;i<ysteps;++i) {
    for(j=0;j<x_points+2;++j)
      printf("%.2f  ",ar[0][i][j]);
    printf("\n");
  }
  printf("\n");

  switch (rank) {
    case 0:
      for(i=1;i<ysteps-1;++i) temp[i-1] = ar[0][i][x_points];
      MPI_Send(temp, ysteps-1, MPI_DOUBLE, 1, TAG, MPI_COMM_WORLD);
      MPI_Recv(temp, ysteps-1, MPI_DOUBLE, 1, TAG, MPI_COMM_WORLD, &stat);
      for(i=1;i<ysteps-1;++i) ar[0][i][x_points+1] = temp[i-1];
      break;
    default:
    if(rank == size-1) {
      if((size-1)%2 == 0) {
        for(i=1;i<ysteps-1;++i) temp[i-1] = ar[0][i][1];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, size-2, TAG, MPI_COMM_WORLD);
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, size-2, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) ar[0][i][0] = temp[i-1];        
      } else {
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, size-2, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) ar[0][i][0] = temp[i-1];
        for(i=1;i<ysteps-1;++i) temp[i-1] = ar[0][i][1];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, size-2, TAG, MPI_COMM_WORLD);        
      }
    } else {
      if(rank%2 == 0) {
        for(i=1;i<ysteps-1;++i) temp[i-1] = ar[0][i][x_points];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, rank+1, TAG, MPI_COMM_WORLD);
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, rank+1, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) ar[0][i][x_points+1] = temp[i-1];

        for(i=1;i<ysteps-1;++i) temp[i-1] = ar[0][i][1];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, rank-1, TAG, MPI_COMM_WORLD);
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, rank-1, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) ar[0][i][0] = temp[i-1];
      } else { 
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, rank-1, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) ar[0][i][0] = temp[i-1];
        for(i=1;i<ysteps-1;++i) temp[i-1] = ar[0][i][1];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, rank-1, TAG, MPI_COMM_WORLD);        

        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, rank+1, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) ar[0][i][x_points+1] = temp[i-1];
        for(i=1;i<ysteps-1;++i) temp[i-1] = ar[0][i][x_points];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, rank+1, TAG, MPI_COMM_WORLD);        
      }
      }
      break;
  }
  
  printf("rank is %d, output\n",rank);
  for(i=0;i<ysteps;++i) {
    for(j=0;j<x_points+2;++j)
      printf("%.2f  ",ar[0][i][j]);
    printf("\n");
  }
  MPI_Finalize();
  return 0;
}  
